#ifndef __MY_UTIL__ // 防止头文件重复包含
#define __MY_UTIL__

#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
#include <sys/stat.h>
#include <jsoncpp/json/json.h>
#include <memory>

namespace aod
{
    // 服务端文件工具类的实现
    // 因为要上传文件，所以先要把上传的文件存起来
    class FileUtil
    {
    public:
        FileUtil(const std::string &name) : _name(name) {}
        // 判断文件是否存在
        bool Exists()
        {
            // 直接使用系统函数, access的F_OK专门用于检测文件是否存在 -- 存在就返回0
            int ret = access(_name.c_str(), F_OK);
            if (ret != 0)
                return false;

            return true;
        }
        // 文件大小
        size_t Size()
        {
            // 文件不存在，直接返回0
            if (this->Exists() == false)
            {
                std::cout << "file not exist!\n";
                return 0;
            }
            // stat接口用于获取文件属性，其中st_size就是文件的大小
            struct stat st;
            int ret = stat(_name.c_str(), &st);
            if (ret != 0)
            {
                std::cout << "get file stat failed!\n";
                return 0;
            }

            return st.st_size;
        }
        // 输出型参数，读取数据文件到bady里
        bool GetContent(std::string *body)
        {
            std::ifstream ifs;
            ifs.open(_name, std::ios::binary); // 视频，图片等都是超文本，要使用二进制方式进行读取
            if (ifs.is_open() == false)
            {
                std::cout << "open file failed!\n";
                return false;
            }
            size_t flen = this->Size();
            body->resize(flen);
            ifs.read((char *)&body[0], flen);
            if (ifs.good() == false)
            {
                std::cout << "read content failed!\n";
                return false;
            }
            ifs.close();
            return true;
        }
        // 向文件写入数据
        bool SetContent(const std::string &body)
        {
            std::ofstream ofs;
            ofs.open(_name, std::ios::binary); // 视频，图片等都是超文本，要使用二进制方式进行读取
            if (ofs.is_open() == false)
            {
                std::cout << "open file failed!\n";
                return false;
            }
            ofs.write(body.c_str(), body.size());
            if (ofs.good() == false)
            {
                std::cout << "write content failed!\n";
                return false;
            }
            ofs.close();
            return true;
        }
        // 针对目录是创建目录
        bool CreateDirectory()
        {
            if (this->Exists())
                return true; // 文件已经存在了，就不需要再创建了
            mkdir(_name.c_str(), 0777);
            return true;
        }

    private:
        std::string _name; // 文件路径名
    };

    // Json 实⽤⼯具类设计
    // 序列化和反序列化
    class JsonUtil
    {
    public:
        static bool Serialize(const Json::Value &val, std::string *body)
        {
            Json::StreamWriterBuilder swb;
            swb["emitUTF8"] = true;
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());

            std::stringstream ss;
            int ret = sw->write(val, &ss); // 把val序列化的结果放进ss里
            if (ret != 0)
            {
                std::cout << "Serialize fail!\n";
                return false;
            }
            *body = ss.str();
            return true;
        }

        static bool UnSerialize(const std::string &body, Json::Value *val)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());

            std::string err;
            bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), val, &err);
            if (ret == false)
            {
                std::cout << "UnSerialize fail!\n";
                return false;
            }
            return true;
        }
    };
}

#endif